#ifndef _MB_TYPE_H_
#define _MB_TYPE_H_

#include <stdio.h>
#include <string.h>

/* ======================== 硬件 / 配置相关 =========================== */

/* 包含硬件相关的具体驱动头文件 */
/* -------- on chip / board -------- */
#include "usart.h"
#include "gpio.h"    /* 点灯调试 */
#include "rom.h"
#include "spiflash.h"
#include "qspiflash.h"

/* ---------------------- 公共配置 ---------------------- */

/* 将固件数据搬移至ROM的起始地址 */ 
#define MB_FW_MOVE2ROM_START_ADDR     FLASH_BANK1_BASE

/* 外部存储设备映射地址 */ 
#define MB_FW_QSPI_STO_MMAP_ADDR      QSPI_BASE

/* 名字长度 */
#define MB_NAME_BUF_LEN           20

/* 固件没次读写默认长度 */
#define MB_FW_RW_LEN_DEF          256    /* 每次默认读写1页 */
#define MB_FW_MAX_SIZE            200000 /* 默认固件大小 2M */

/* 最大数值 */
#define MB_MAX_NBR                0xFFFFFFFF

/* 是否启动测试功能 (会造成大量内存占用) */
#define MB_ENBALE_TEST

#define LED_B_ON     HAL_GPIO_WritePin(LED_B_GPIO_Port, LED_B_Pin, GPIO_PIN_RESET)
#define LED_B_OFF    HAL_GPIO_WritePin(LED_B_GPIO_Port, LED_B_Pin, GPIO_PIN_SET)
#define LED_R_ON     HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET)
#define LED_R_OFF    HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_SET)

/* ---------------------- CMC 配置 ---------------------- */

/* CMC_SELECT 最大序号 (需与 CMC_SELECT 枚举中的值一致) */
#define CMC_SELECT_MAX_NBR  5

/* 数据通信方式 */
typedef enum
{
    CMC_USART = 0,                /* 串口 */
    CMC_NET,                      /* 有线网口 */
    CMC_WIFI,                     /* WIFI */
    CMC_LORA,                     /* LoRa */
    CMC_4G,                       /* 4G */
    CMC_UNKNOWN = (CMC_4G + 1),   /* 未知设备 */
} CMC_SELECT;

/* 数据通信方式的宏定义 (和枚举值一致， 因为预编译阶段, 枚举类型值无效) */
#define CMC_USART_DEF      0                /* 串口 */
#define CMC_NET_DEF        1                /* 有线网口 */
#define CMC_WIFI_DEF       2                /* WIFI */
#define CMC_LORA_DEF       3                /* LoRa */
#define CMC_4G_DEF         4                /* 4G */
#define CMC_UNKNOWN_DEF    (CMC_4G_DEF + 1) /* 未知设备 */

/* CMC 设备名字 */
#define CMC_USART_NAME     "CMC_USART"       /* 串口 */
#define CMC_NET_NAME       "CMC_NET"         /* 有线网口 */
#define CMC_WIFI_NAME      "CMC_WIFI"        /* WIFI */
#define CMC_LORA_NAME      "CMC_LORA"        /* LoRa */
#define CMC_4G_NAME        "CMC_4G"          /* 4G */

/* CMC 用户交互显示列表 */
#define CMC_HCI_DEV_LIST   "   (0: UART, 1: NET, 2: WIFI, 3: LORA, 4: 4G)\n"

/* 顺序有关, 未使用的, 必须设置为 CMC_UNKNOWN */
#define CMC_DEV_SELS_INIT_CFG   {CMC_UNKNOWN_DEF, CMC_UNKNOWN_DEF, CMC_UNKNOWN_DEF, CMC_UNKNOWN_DEF, CMC_UNKNOWN_DEF}
#define CMC_DEV_SELS_CFG        {CMC_USART_DEF, CMC_UNKNOWN_DEF, CMC_UNKNOWN_DEF, CMC_UNKNOWN_DEF, CMC_UNKNOWN_DEF}

/* 设置 CMC 设备名字 (一般是用于调试展示) */
#define CMC_DEV_NAME_SET(sel, namebuf)             \
    {                                              \
        switch (sel)                               \
        {                                          \
            case CMC_USART_DEF:                    \
            {                                      \
                memcpy(namebuf, CMC_USART_NAME,    \
                       strlen(CMC_USART_NAME));    \
            } break;                               \
                                                   \
            case CMC_NET_DEF:                      \
            {                                      \
                memcpy(namebuf, CMC_NET_NAME,      \
                       strlen(CMC_NET_NAME));      \
            } break;                               \
                                                   \
            case CMC_WIFI_DEF:                     \
            {                                      \
                memcpy(namebuf, CMC_WIFI_NAME,     \
                       strlen(CMC_WIFI_NAME));     \
            } break;                               \
                                                   \
            case CMC_LORA_DEF:                     \
            {                                      \
                memcpy(namebuf, CMC_LORA_NAME,     \
                       strlen(CMC_LORA_NAME));     \
            } break;                               \
                                                   \
            case CMC_4G_DEF:                       \
            {                                      \
                memcpy(namebuf, CMC_4G_NAME,       \
                       strlen(CMC_4G_NAME));       \
            } break;                               \
                                                   \
            default: break;                        \
        }                                          \
    }

/* ---------------------- STO 配置 ---------------------- */

/* STO_SELECT 最大序号 (需与 STO_SELECT 枚举中的值一致) */
#define STO_SELECT_MAX_NBR  4

/* 存储固件的设备 */
typedef enum
{
    STO_ROM = 0,                      /* 片内ROM */
    STO_SPIFLASH,                     /* 片外SPI FLASH */
    STO_QSPIFLASH,                    /* 片外QSPI FLASH */
    STO_SDCARD,                       /* SD卡 */
    STO_UNKNOWN = (STO_SDCARD + 1),   /* 未知设备 */
} STO_SELECT;

/* 存储固件设备的宏定义 (和枚举值一致， 因为预编译阶段, 枚举类型值无效) */
#define STO_ROM_DEF        0                       /* 片内ROM */
#define STO_SPIFLASH_DEF   1                       /* 片外SPI FLASH */
#define STO_QSPIFLASH_DEF  2                       /* 片外QSPI FLASH */
#define STO_SDCARD_DEF     3                       /* SD卡 */
#define STO_UNKNOWN_DEF    (STO_SDCARD_DEF + 1)    /* 未知设备 */

/* STO 设备名字 (一般是用于调试展示) */
#define STO_ROM_NAME       "STO_ROM"         /* 片内ROM */
#define STO_SPIFLASH_NAME  "STO_SPIFLASH"    /* 片外SPI FLASH */
#define STO_QSPIFLASH_NAME "STO_QSPIFLASH"   /* 片外QSPI FLASH */
#define STO_SDCARD_NAME    "STO_SDCARD"      /* SD卡 */

/* STO 用户交互显示列表 */
#define STO_HCI_DEV_LIST   "   (0: ROM, 1: SPIFLASH, 2: QSPIFLASH, 3: SDCARD)\n"

/* 顺序有关, 未使用的, 必须设置为 STO_UNKNOWN_DEF */
#define STO_DEV_SELS_INIT_CFG {STO_UNKNOWN_DEF, STO_UNKNOWN_DEF, STO_UNKNOWN_DEF, STO_UNKNOWN_DEF}
#define STO_DEV_SELS_CFG      {STO_UNKNOWN_DEF, STO_UNKNOWN_DEF, STO_QSPIFLASH_DEF, STO_UNKNOWN_DEF}

/* 设置 STO 设备名字 (一般是用于调试展示) */
#define STO_DEV_NAME_SET(sel, namebuf)             \
    {                                              \
        switch (sel)                               \
        {                                          \
            case STO_ROM_DEF:                      \
            {                                      \
                memcpy(namebuf, STO_ROM_NAME,      \
                       strlen(STO_ROM_NAME));      \
            } break;                               \
                                                   \
            case STO_SPIFLASH_DEF:                 \
            {                                      \
                memcpy(namebuf, STO_SPIFLASH_NAME, \
                       strlen(STO_SPIFLASH_NAME)); \
            } break;                               \
                                                   \
            case STO_SDCARD_DEF:                   \
            {                                      \
                memcpy(namebuf, STO_SDCARD_NAME,   \
                       strlen(STO_SDCARD_NAME));   \
            } break;                               \
                                                   \
            default:break;                         \
        }                                          \
    }

/* -------------------- PROT 数据解析协议配置 -------------------- */

/* PROT_SELECT 最大序号 (需与 PROT_SELECT 枚举中的值一致) */
#define PROT_SELECT_MAX_NBR  2

/* 选择数据帧协议 */
typedef enum
{
    PROT_XMODEM = 0,                    /* XMODEM协议 */
    PROT_YMODEM,                        /* YMODEM协议 */
    PROT_UNKNOWN = (PROT_YMODEM + 1),   /* 未知数据帧协议 */
} PROT_SELECT;

/* 选择数据帧协议的宏定义 (和枚举值一致， 因为预编译阶段, 枚举类型值无效) */
#define PROT_XMODEM_DEF    0    /* XMODEM 协议 (128Bytes) */
#define PROT_YMODEM_DEF    1    /* YMODEM 协议 (1024Bytes) */
#define PROT_UNKNOWN_DEF   (PROT_YMODEM_DEF + 1)    /* 未知协议 */

/* PROT 设备名字 (一般是用于调试展示) */
#define PROT_XMODEM_NAME   "PROT_XMODEM"         /* XMODEM 协议 */
#define PROT_YMODEM_NAME   "PROT_YMODEM"         /* YMODEM 协议 */
#define PROT_UNKNOWN_NAME  "PROT_UNKNOWN"        /* 未知协议 */

/* PROT 用户交互显示列表 */
#define PROT_HCI_TYPE_LIST  "   (0: XMODEM, 1: YMODEM)\n"

/* 顺序有关, 暂不支持两种协议同时存在 */
#define PROT_SELS_INIT_CFG  {PROT_UNKNOWN_DEF, PROT_UNKNOWN_DEF}
#define PROT_SELS_CFG       {PROT_XMODEM_DEF, PROT_UNKNOWN_DEF}
#define PROT_PAYLOAD_SIZE   128         /* xmodem 有效数据 128字节 */

/* 根据协议设置收发数据缓冲区最大长度 */
#if (PROT_SEL_CFG == PROT_XMODEM_DEF)
#define PROT_TXBUF_MAX_LEN  128
#define PROT_RXBUF_MAX_LEN  384
#elif (PROT_SEL_CFG == PROT_YMODEM_DEF)
#define PROT_TXBUF_MAX_LEN  128
#define PROT_RXBUF_MAX_LEN  2560
#endif

/* 设置 PROT 协议名字 (一般是用于调试展示) */
#define PROT_NAME_SET(sel, namebuf)                \
    {                                              \
        switch (sel)                               \
        {                                          \
            case PROT_XMODEM_DEF:                  \
            {                                      \
                memcpy(namebuf, PROT_XMODEM_NAME,  \
                       strlen(PROT_XMODEM_NAME));  \
            } break;                               \
                                                   \
            case PROT_YMODEM_DEF:                  \
            {                                      \
                memcpy(namebuf, PROT_YMODEM_NAME,  \
                       strlen(PROT_YMODEM_NAME));  \
            } break;                               \
                                                   \
            default:break;                         \
        }                                          \
    }

/* 协议帧各字节含义 (DX: DATA XFR) */
#define PROT_DX_FORMAT_SOH      0x01      /* Xmodem数据头 */
#define PROT_DX_SBYTE_REQUEST   'C'       /* 开始请求 Xmodem 协议传输 */
#define PROT_DX_SBYTE_EOT       0x04      /* Master: 发送结束 (单字节指令) */
#define PROT_DX_SBYTE_ACK       0x06      /* Slave: 成功应答 (单字节指令) */
#define PROT_DX_SBYTE_NACK      0x15      /* Slave: 失败应答 (单字节指令) */
#define PROT_DX_SBYTE_CAN       0x18      /* Master: 终止传输 (单字节指令) */
#define PROI_DX_PAYLOAD_LEN     128       /* 每帧数据中 有效数据个数 */

#define PROT_SBYTE_LEN          1          /* 单字节命令时, 接收到数据的长度 */
    
/* slave 发送的周期计数值 */
#define PROT_REQUEST_PERIOD_CNT 900000      /* 1.5s */

/* 特殊数据的识别 */
#define PROT_DX_DATA_FILL_MARK        0x1A       /* 最后一帧协议填充的数据以补足 PROI_DX_PAYLOAD_LEN 字节 */
#define PROT_CHECK_FILL_MARK_MAX_NBR  4          /* 检测连续到 4 个 (个数并不准确) 0x1A, 表示该帧后面的数据是被填充了的 */

/* ---------------------- MBOOT设备的配置信息 ---------------------- */

/* 禁止在MBOOT中初始化硬件 (工程已提供初始化的前提) */
//#undef MB_DEV_DISABLE_INIT
#define MB_DEV_DISABLE_INIT

/* ---------------------- CMC 设备相关配置 ---------------------- */

/* ------ CMC_USART ------ */
#define CMC_USART_BAUDRATE   115200         /* 串口波特率 */

/* ------- CMC_NET ------- */

/* ------ CMC_WIFI ------- */

/* ------ CMC_LORA ------- */

/* ------- CMC_4G -------- */

/* ---------------------- STORE 设备相关配置 ---------------------- */

/* ---------- STO_ROM --------- */

/* ------- STO_SPIFLASH ------- */

/* ------- STO_QSPIFLASH ------ */

/* -------- STO_SDCARD -------- */

/* ---------------------- 用户交互 相关配置 ---------------------- */

#define HCI_TXBUF_MAX_LEN      512   /* 数据发送缓冲区 */
#define HCI_RXBUF_MAX_LEN      32    /* 数据接收缓冲区 */
#define HCI_CMC_SELECT_DEFAULT CMC_USART_DEF    /* HCI数据通道选择 */

/*
 *
 *
 * ///////////////////////////// 分割线 /////////////////////////////
 * 
 * 
 */


/* ========================== 数据类型 ============================= */

/* ---------------------- 公共数据类型 ---------------------- */

typedef struct MB_BUF_ATTR_STR
{
    uint8_t * buf;
    uint32_t  len;
} mb_buf_attr;

typedef struct MB_ADDR_ATTR_STR
{
    uint32_t addr;
    uint32_t len;
} mb_addr_attr;

typedef enum
{
    MB_TRUE    = 0,
    MB_FALSE   = 1,
    MB_UNKNOWN = 2,
} MB_STATUS;

#define MB_TRUE_DEF      0
#define MB_FALSE_DEF     1
#define MB_UNKNOWN_DEF   2

/* 数据传输/升级状态 */
typedef enum
{
    MB_XFR_NOTSTART = 0,    /* 未开始 */
    MB_XFR_START,           /* 已开始 (发出请求) */
    MB_XFR_ING,             /* 进行中 */
    MB_XFR_FINISHED,        /* 完成 */
    MB_XFR_MODERR,          /* 模块异常 */
    MB_XFR_CANCELED,        /* 被取消 */
} MB_XFR_STATUS;

typedef union
{
    uint32_t nbr;
    uint8_t  buf[4];
} mb_4bufu;

/* ---------------------- CMC 设备操作函数 ---------------------- */

/* CMC 设备操作 */
typedef struct CMC_OP_STR
{
    int (*set_rxbuf_attr)(mb_buf_attr * buf_attr);  /* 设置接收缓冲区信息 */
    int (*set_txbuf_attr)(mb_buf_attr * buf_attr);  /* 设置发送缓冲区信息 */
    void (*start_recv)(void);                       /* 开始接收数据 */
    MB_STATUS (*check_is_rxed)(void);               /* 检测是否收到数据 */
    MB_STATUS (*check_is_txed)(void);               /* 检测是否发送完数据 */
    mb_buf_attr *(*get_txbuf)(void);                /* 获得 txbuf 缓冲区地址 */
    mb_buf_attr *(*get_data)(void);                 /* 获得 rxbuf 的数据 */
    void (*put_data)(mb_buf_attr * buf_attr);       /* 往串口写入数据 */
} cmc_op, *cmc_op_t;

/* CMC 设备操作注册函数类型 */
typedef cmc_op *(*cmc_op_register)(void);

/* 某个 CMC 设备操作函数 及 操作函数的状态 */
typedef struct CMC_OP_STATUS_STR
{
    cmc_op *  op;                    /* 操作函数 */
    char      name[MB_NAME_BUF_LEN]; /* 名字(用于调试) */
    MB_STATUS is_can_use;            /* 操作函数状态 */
} cmc_op_status, *cmc_op_status_t;

/* ---------------------- STO 设备操作函数 ---------------------- */

/* STO 设备操作 */
typedef struct STO_OP_STR
{
    mb_addr_attr * (*take_free_space)(uint32_t size);         /* 获得一片空间 */
    MB_STATUS (*erase_space)(uint32_t addr);                  /* 擦除这片空间 */
    int (*put_data)(mb_buf_attr * buf, uint32_t addr);        /* 写(存入)数据 */
    mb_buf_attr * (*get_data)(uint32_t addr, uint16_t nbr);   /* 读(读取)数据 */
    int (*memory_mapped)(void);                           /* 内存映射 */
} sto_op, *sto_op_t;

/* CMC 设备操作注册函数类型 */
typedef sto_op *(*sto_op_register)(void);

/* 某个 STO 设备操作函数 及 操作函数的状态 */
typedef struct STO_OP_STATUS_STR
{
    sto_op *  op;                    /* 操作函数 */
    char      name[MB_NAME_BUF_LEN]; /* 名字(用于调试) */
    MB_STATUS is_can_use;            /* 操作函数状态 */
} sto_op_status, *sto_op_status_t;

/* ---------------------- 数据解析协议类型 ---------------------- */

/* (xmodem/ymodem) 协议帧格式 */
typedef struct PROT_FORMAT_STR
{
    uint8_t  head;       /* 帧头 */
    uint8_t  index;      /* 帧序号 */
    uint8_t  invindex;   /* 帧序号按位求反 */
    uint8_t  *payload;   /* 负载 (有效数据) */
    uint16_t payload_len;   /* 负载数据长度 */
    uint8_t  crc_h;      /* CRC 校验高8位 */
    uint8_t  crc_l;      /* CRC 校验低8位 */
} prot_format, *prot_format_t;

/* PROT 协议的操作函数 */
typedef struct PROT_OP_STR
{
    int (*carrier_init)(cmc_op *op);              /* 初始化数据通信通道 */
    mb_buf_attr * (*transfer_and_parse)(void);    /* 帧解析出有效数据 */
    MB_XFR_STATUS (*get_xfr_status)(void);        /* 获得数据传输状态 */
} prot_op, *prot_op_t;

/* PROT 操作函数 及 操作函数的状态 */
typedef struct PROT_OP_STATUS_STR
{
    prot_op * op;                    /* 操作函数 */
    char      name[MB_NAME_BUF_LEN]; /* 名字(用于调试) */
    MB_STATUS is_can_use;            /* 操作函数状态 */
} prot_op_status, *prot_op_status_t;

/* ---------------------- 数据存储类型 ---------------------- */

/* STORE 的操作函数 */
typedef struct STORE_OP_STR
{
    int (*carrier_init)(sto_op *op);                    /* 初始化数据存储通道 */
    void (*take_free_space)(uint32_t size);             /* 从所选择的数据载体中拿到指定大小的空闲空间  */
    MB_XFR_STATUS (*store_firmware)(mb_buf_attr * buf_attr);    /* 保存 (存入) 固件 */
    mb_buf_attr * (*get_firmware)(void);                           /* 读出固件 */
    void (*store_firmware_size)(void);                          /* 保存固件大小(字节) */
    uint32_t (*get_firmware_size)(void);                        /* 获得 固件大小 (字节) */
    int (*memory_mapped)(void);                                /* 内存映射(针对从片外存储设备启动) */
} store_op, *store_op_t;

/* STORE 操作函数 及 操作函数的状态 */
typedef struct STORE_OP_STATUS_STR
{
    store_op * op;                    /* 操作函数 */
    MB_STATUS  is_can_use;            /* 操作函数状态 */
} store_op_status, *store_op_status_t;

/* ---------------------- 重启前操作类型 ---------------------- */

/* 检测一些超时行为 */
typedef struct CHECK_TIMEOUT_STR
{
    uint32_t curtick;
    uint32_t settick;
} check_timeout;

/* preboot 的操作函数 */
typedef struct PREBOOT_OP_STR
{
    int (*memory_mapped)(void);                      /* 内存映射(针对从片外存储设备启动) */
    int (*load_firmware)(uint32_t start_addr);       /* 加载固件 (往ROM写入) */
    void (*system_deinit)(uint32_t vtor);            /* 系统去初始化 */
} preboot_op, *preboot_op_t;

/* ---------------------- 用户交互 ---------------------- */

/* 从一个数值中的bit域解析出指令 */
#define HCI_1ST_REQ_BIT_DEDOMAIN(x)     ((x & 0xF0) >> 4)   /* 1111 */
#define HCI_2ND_REQ_BIT_DEDOMAIN(x)     ((x & 0x0E) >> 1)   /* 111 */
#define HCI_3RD_REQ_BIT_DEDOMAIN(x)     ((x & 0x01) >> 0)   /* 1 */

typedef enum
{
    HCI_REQ_SELECT_PROT = 1,
    HCI_REQ_SELECT_CMC  = 2,
    HCI_REQ_SELECT_STO  = 3,
    HCI_REQ_UPDATE_FW   = 4,
    HCI_REQ_ENTRY_APP   = 5,
    HCI_REQ_RESET       = 6,
    HCI_REQ_EXIT_BOOT   = 7,
} HCI_ACTIONS;

/* 用户输入的指令帧 */
typedef struct HCI_FORMAT_STR
{
    uint8_t cmd_1st;
    uint8_t or1;
    uint8_t cmd_2nd;
    uint8_t or2;
    uint8_t cmd_3rd;
} hci_format, *hci_format_t;

typedef struct HCI_REQ_STR
{
    MB_STATUS  is_reselect;  /* 用户请求重新输入 */
    uint8_t    nbr;          /* 用户请求的项目个数 */
    uint16_t   bits;         /* 用户的请求项(bit) */
} hci_req;

/* 用户交互相关操作 */
typedef struct HCI_OP_STR
{
    int (*carrier_init)(cmc_op *op);  /* 初始化人机通信通道 */
    MB_STATUS (*wait_abort)(MB_STATUS SHOW_NOTICE);    /* 等待用户打断事件 */
    int (*menu_show)(void);          /* 菜单显示 */
    hci_req * (*select_parse)(void);   /* 处理用户输入选择 */
    MB_STATUS (*response)(MB_STATUS OP_RESULT);    /* 反馈用户操作结果 */
    MB_STATUS (*check_is_timeout)(uint32_t timeout); /* 检测行为在指定时间后是否超时 */
} hci_op, *hci_op_t;

/* HCI 操作函数 及 操作函数的状态 */
typedef struct HCI_OP_STATUS_STR
{
    hci_op * op;              /* 操作函数 */
    MB_STATUS  is_can_use;    /* 操作函数状态 */
} hci_op_status, *hci_op_status_t;

#endif
